#include "analysis_modbus.h"

analysis_modbus::analysis_modbus()
{
    m_thread = new QThread();
    this->moveToThread(m_thread);
    m_thread->start();
}
analysis_modbus::~analysis_modbus()
{
    if (m_thread->isRunning())
    {
        m_thread->quit();
        m_thread->wait();
        while (true == m_thread->isRunning());
    }
    readseting->deleteLater();
    m_thread->deleteLater();
}
//接收报文
void analysis_modbus::recvModbusMsg(QByteArray msg,quint8 addr)
{
    qDebug()<<"数据解析线程:"<<QThread::currentThreadId();
    readseting = new QSettings("dataini/Data.ini", QSettings::IniFormat);
    if(msg.isEmpty()==false)
    {
        mb_addr = addr;
        recvModbusmsg = msg;
        MB_satae state =parse_Modbus_Msg(recvModbusmsg);
        qDebug()<< state;
        parse_Modbus_MB_satae(state);
    }
}
//读取状态
MB_satae analysis_modbus::parse_Modbus_Msg(QByteArray ba)
{
    qDebug() << ba.toHex().toUpper()  << ba.length() <<endl;
    //判断帧长度
    if(ba.length()>256||ba.length()<8)
    {
        errorMsg = "报文长度过长或过短不正确 Lenghtrerror";
        qDebug()<< "Lenghtrerror";
        return MB_SLAVE_STATE_PACKET_OTHER;
    }
    //计算帧数据字节是否和数据长度正确
    //线圈字节数
    quint8 csize = (quint8)ba.at(6);
    //寄存器字节数
    quint8 rsize = (quint8)ba.at(6);
    //去除校验码
    QByteArray bass = ba.mid(0,ba.size()-2);
    //数据段长度
    QByteArray dsize = bass.mid(7,bass.size());
    //写入数据数量
    wnum = BondTwoUint8ToUint16((quint8)ba.at(4),(quint8)ba.at(5));
    //判断从机地址
    if(ba[0]!= mb_addr)
    {
        errorMsg = "不是给本机的 Addrerror";
        qDebug()<< "this is Addrerror";
        return MB_SLAVE_STATE_PACKET_OTHER;
    }
    auto crc16ForModbus = JQChecksum::crc16ForModbus(ba,CRC_FLAG);
    qDebug() << "crc16ForModbus:"   << crc16ForModbus   << QString::number( crc16ForModbus, 16 ).toUpper();
    auto bus=  ba.mid(ba.length()-2,ba.length());
    auto crcl = crc16ForModbus&0xFF; //crc低位
    auto crch = crc16ForModbus>>8;//crc高位
    quint8 crchs = bus.at(0);//crc高位
    quint8 crcls = bus.at(1);//crc低位
    //判断CRC
    if(crcls!=crcl||crch!=crchs)
    {
        errorMsg = "this is CRCrerror";
        qDebug()<< "校验码错误CRCrerror";
        return MB_SLAVE_STATE_PACKET_OTHER;
    }
    //判断功能码
    switch(ba[1])
    {
    case READER_COIL_CODE: mb_code =READER_COIL_CODE; qDebug()<< "this is 01 function";
        //起始地址
        mb_startaddr = ((quint8)ba[2])*256+(quint8)ba[3];
        //数据量
        mb_num = ((quint8)ba[4])*256+(quint8)ba[5];

        if(mb_num>2000||mb_num==0)
        {
            qDebug()<< "this is dataNumerror";
            errorMsg = "03异常数据数量错误 dataNumerror";
            return MB_SLAVE_STATE_DATA_ERROR;
        }else
            if((mb_startaddr+mb_num-1)>65535)
            {
                qDebug()<< "this is dataAddrerror";
                errorMsg = "02异常数据地址错误 dataAddrerror";
                return MB_SLAVE_STATE_DATAADDR_ERROR;
            }
            else if(ba.length()>8)
            {
                errorMsg = "读取报文长度 Lenghtrerror";
                qDebug()<< "this is Lenghtrerror";
                return MB_SLAVE_STATE_PACKET_OTHER;
            }
            else
            {
                return MB_SLAVE_STATE_PACKET_PROCESS;
            }
        break;
    case Read_REGISTER:mb_code=Read_REGISTER;qDebug()<< "this is 03 function";
        //起始地址
        mb_startaddr = ((quint8)ba[2])*256+(quint8)ba[3];
        //数据量
        mb_num = ((quint8)ba[4])*256+(quint8)ba[5];
        if(mb_num>125||mb_num==0)
        {
            qDebug()<< "this is dataNumerror";
            errorMsg = "03异常数据数量错误 dataNumerror";
            return MB_SLAVE_STATE_DATA_ERROR;
        }else
            if((mb_startaddr+mb_num-1)>65535)
            {
                qDebug()<< "this is dataAddrerror";
                errorMsg = "02异常数据地址错误 dataAddrerror";
                return MB_SLAVE_STATE_DATAADDR_ERROR;
            }
            else if(ba.length()>8)
            {
                errorMsg = "读取报文长度不正确Lenghtrerror";
                qDebug()<< "this is Lenghtrerror";
                return MB_SLAVE_STATE_PACKET_OTHER;
            }
            else
            {
                return MB_SLAVE_STATE_PACKET_PROCESS;
            }
        break;
    case WRITE_COIL:mb_code =WRITE_COIL;
        //起始地址
        mb_startaddr = ((quint8)ba[2])*256+(quint8)ba[3];
        //数据量
        mb_num = ((quint8)ba[4])*256+(quint8)ba[5];
        qDebug()<< "this is 0f function" << mb_code << mb_num;
        if(mb_num>1968||mb_num==0)
        {
            qDebug()<< "this is dataNumerror";
            errorMsg = "03异常数据数量错误 dataNumerror";
            return MB_SLAVE_STATE_DATA_ERROR;
        }else
            if((mb_startaddr+mb_num-1)>65535)
            {
                qDebug()<< "this is dataAddrerror";
                errorMsg = "02异常数据地址错误 dataAddrerror";
                return MB_SLAVE_STATE_DATAADDR_ERROR;
            }
            else if(csize!=dsize.size()||((wnum+7)/8)!=csize)
            {
                errorMsg = "写入字节与数据段长度或数量与字节数不正确 Lenghtrerror";
                qDebug()<< "this is Lenghtrerror";
                return MB_SLAVE_STATE_PACKET_OTHER;
            }
            else
            {
                return MB_SLAVE_STATE_PACKET_PROCESS;
            }
        break;
    case WRITE_REGISTER:mb_code =WRITE_REGISTER;qDebug()<< "this is 10 function";
        //起始地址
        mb_startaddr = ((quint8)ba[2])*256+(quint8)ba[3];
        //数据量
        mb_num = ((quint8)ba[4])*256+(quint8)ba[5];
        qDebug() << mb_num;
        if(mb_num>123||mb_num==0)
        {
            qDebug()<< "this is dataNumerror";
            errorMsg = "03异常数据数量错误 dataNumerror";
            return MB_SLAVE_STATE_DATA_ERROR;
        }else
            if((mb_startaddr+mb_num-1)>65535)
            {
                qDebug()<< "this is dataAddrerror";
                errorMsg = "02异常数据地址错误 dataAddrerror";
                return MB_SLAVE_STATE_DATAADDR_ERROR;
            }
            else if(rsize!=dsize.size()||(wnum*2!=rsize))
            {
                errorMsg = "写入字节与数据段长度或数量与字节数不正确 Lenghtrerror";
                qDebug()<< "this is Lenghtrerror";
                return MB_SLAVE_STATE_PACKET_OTHER;
            }
            else
            {
                return MB_SLAVE_STATE_PACKET_PROCESS;
            }
        break;
    default:
        errorMsg = "功能码不支持 functionerror";
        mb_code = ba[1];
        return MB_SLAVE_STATE_FUNCTION_ERROR;
        break;
    }
}
//状态处理
void analysis_modbus::parse_Modbus_MB_satae(MB_satae satae)
{
    switch(satae)
    {
    case MB_SLAVE_STATE_PACKET_PROCESS:
        switch(mb_code)
        {
        case 1:func_01();
            break;
        case 3:func_03();
            break;
        case 15:func_0f();
            break;
        case 16:func_10();
            break;
        }
        break;
        //异常处理
    case MB_SLAVE_STATE_DATAADDR_ERROR:
        parse_Modbus_Exception_Handling02();
        emit toUishowMsg(errorMsg);
        break;
    case MB_SLAVE_STATE_DATA_ERROR:
        parse_Modbus_Exception_Handling03();
        emit toUishowMsg(errorMsg);
        break;
    case MB_SLAVE_STATE_FUNCTION_ERROR:
        parse_Modbus_Exception_Handling01();
        emit toUishowMsg(errorMsg);
        break;
    case MB_SLAVE_STATE_PACKET_OTHER:
        emit toUishowMsg(errorMsg);
        break;
    }
}
//正常帧处理
void analysis_modbus::func_01()
{
    QByteArray ba;
    quint16 num =((quint8)recvModbusmsg[4])*256+(quint8)recvModbusmsg[5];
    quint16 startaddr =((quint8)recvModbusmsg[2])*256+(quint8)recvModbusmsg[3];
    GetData0X01(ba,startaddr,num);
    //单元标识符
    sendModbusmsg[0]=recvModbusmsg[0];
    //功能码
    sendModbusmsg[1]=recvModbusmsg[1];
    //字节计数
    sendModbusmsg[2]=(quint8)ba.size();
    //状态值
    for(int i=3,j=0;j<ba.size();j++)
    {
        sendModbusmsg[i++]=(quint8)ba.at(j);
    }
    //显示读出的数据
    ReadCoilPackMsgToShow(startaddr,num,ba);
    //CRC校验
    QByteArray crcba(sendModbusmsg,5+(quint8)ba.size());
    quint16 crc16 = crc16ForModbus(crcba,CRC_FLAG);
    //CRC校验高位
    sendModbusmsg[3+(quint8)ba.size()] = crc16>>8;
    //CRC校验低位
    sendModbusmsg[4+(quint8)ba.size()] = crc16&0xFF;
    emit toUishowMsgPack(sendModbusmsg);
    emit analysis_over(sendModbusmsg);
    sendModbusmsg.clear();
}

void analysis_modbus::func_03()
{
    quint16 num =((quint8)recvModbusmsg[4])*256+(quint8)recvModbusmsg[5];
    quint16 startaddr =((quint8)recvModbusmsg[2])*256+(quint8)recvModbusmsg[3];
    //单元标识符
    sendModbusmsg[0]=recvModbusmsg[0];
    //功能码
    sendModbusmsg[1]=recvModbusmsg[1];
    //字节计数
    sendModbusmsg[2]=(quint8)num*2;
    //状态值
    for(quint16 i=3,z=0,j=startaddr;z<num;z++,j++)
    {
        //读出寄存器数据
        QString registerData = readseting->value("Section" + QString::number(j+1) + "/regi").toString();
        sendModbusmsg[i++]=((quint16)registerData.toInt())>>8;
        sendModbusmsg[i++]=((quint16)registerData.toInt())&0xFF;
        msg.push_back((quint16)registerData.toInt());
    }
    ReadRegsPackMsgToShow(startaddr,num,msg);
    //CRC校验
    QByteArray crcba(sendModbusmsg,5+num*2);
    quint16 crc16 = crc16ForModbus(crcba,CRC_FLAG);
    //CRC校验高位
    sendModbusmsg[3+num*2] = crc16>>8;
    //CRC校验低位
    sendModbusmsg[4+num*2] = crc16&0xFF;
    emit toUishowMsgPack(sendModbusmsg);
    emit analysis_over(sendModbusmsg);
    sendModbusmsg.clear();
}

void analysis_modbus::func_0f()
{
    qDebug()<<"0f解析线程:"<<QThread::currentThreadId();
    QByteArray ba;
    quint16 startaddr =((quint8)recvModbusmsg[2])*256+(quint8)recvModbusmsg[3];
    quint16 datanum = ((quint8)recvModbusmsg[4])*256+(quint8)recvModbusmsg[5];
    quint16 sizenum = (quint8)recvModbusmsg[6];
    //读取数据
    for(int i=0;i<sizenum;i++)
    {
        ba[i]=recvModbusmsg[7+i];
    }
    //转化为二进制字符串
    HexByteArrayToBinString(ba);
    //更新表格
    emit wirtTablec(datanum,startaddr,HexByteArrayToBinString(ba));
    //写入文件
    WriteData0X0F(startaddr,HexByteArrayToBinString(ba));
    //读出写入数据
    WirteCoilPackMsgToShow(startaddr,datanum,ba);
    //回应报文
    ba = recvModbusmsg.mid(0,6);
    //CRC校验
    QByteArray crcba(ba,8);
    quint16 crc16 = crc16ForModbus(crcba,CRC_FLAG);
    //CRC校验高位
    ba[6] = crc16>>8;
    //CRC校验低位
    ba[7] = crc16&0xFF;
    emit toUishowMsgPack(ba);
    emit analysis_over(ba);
    bac.clear();
}
void analysis_modbus::func_10()
{
    QByteArray ba;
    quint16 startaddr =((quint8)recvModbusmsg[2])*256+(quint8)recvModbusmsg[3];
    quint16 datanum = ((quint8)recvModbusmsg[4])*256+(quint8)recvModbusmsg[5];
    //读取数据
    for(int j=7,z=0,k=startaddr;z<datanum;k++,z++)
    {
        quint16 coildata=((quint8)recvModbusmsg[j++])*256+(quint8)recvModbusmsg[j++];
        bar.push_back(coildata);
        //写入文件
        QString s = "Section" + QString::number(k+1) + "/regi";
        readseting->setValue(s,coildata);
    }
    //更新表格
    emit wirtTabler(datanum,startaddr,bar);
    WirteRegsPackMsgToShow(startaddr,datanum,bar);
    //回应报文
    ba = recvModbusmsg.mid(0,6);
    //CRC校验
    QByteArray crcba(ba,8);
    quint16 crc16 = crc16ForModbus(crcba,CRC_FLAG);
    //CRC校验高位
    ba[6] = crc16>>8;
    //CRC校验低位
    ba[7] = crc16&0xFF;
    emit toUishowMsgPack(ba);
    emit analysis_over(ba);
    sendModbusmsg.clear();
    bar.clear();
}
//异常处理
void analysis_modbus::parse_Modbus_Exception_Handling01()
{
    QByteArray ba;
    //回应报文
    ba = recvModbusmsg.mid(0,2);
    ba[1] = (mb_code+0x80);
    ba[2] = 0x01;
    //CRC校验
    QByteArray crcba(ba,5);
    quint16 crc16 = crc16ForModbus(crcba,CRC_FLAG);
    //CRC校验高位
    ba[3] = crc16>>8;
    //CRC校验低位
    ba[4] = crc16&0xFF;
    emit toUishowMsgPack(ba);
    emit analysis_over(ba);
}

void analysis_modbus::parse_Modbus_Exception_Handling02()
{
    QByteArray ba;
    //回应报文
    ba = recvModbusmsg.mid(0,2);
    ba[1] = (mb_code+0x80);
    ba[2] = 0x02;
    //CRC校验
    QByteArray crcba(ba,5);
    quint16 crc16 = crc16ForModbus(crcba,CRC_FLAG);
    //CRC校验高位
    ba[3] = crc16>>8;
    //CRC校验低位
    ba[4] = crc16&0xFF;
    emit toUishowMsgPack(ba);
    emit analysis_over(ba);
}

void analysis_modbus::parse_Modbus_Exception_Handling03()
{
    QByteArray ba;
    //回应报文
    ba = recvModbusmsg.mid(0,2);
    ba[1] = (mb_code+0x80);
    ba[2] = 0x03;
    //CRC校验
    QByteArray crcba(ba,5);
    quint16 crc16 = crc16ForModbus(crcba,CRC_FLAG);
    //CRC校验高位
    ba[3] = crc16>>8;
    //CRC校验低位
    ba[4] = crc16&0xFF;
    emit toUishowMsgPack(ba);
    emit analysis_over(ba);
}
//报文线圈数据读出提示
void analysis_modbus::ReadCoilPackMsgToShow(quint16 startaddr,quint16 num,QByteArray msg)
{
    quint8 size = msg.size();
    QString msgs;
    for(quint8 i=0;i<size;i++)
    {
        //先转化为2进制字符串
        QString str = QString::number((quint8)msg.at(i),2);
        //再转化为2进制整形，由二进制整形转化为8位2进制字符串前面自动补0，从而保证8位
        str = QString("%1").arg((quint8)str.toInt(NULL,2),8,2,QChar('0'));
        //8bit字节倒转
        byteReverse(str);
        //添加到数据中
        msgs += str;
    }
    //去除填充的0位，读出请求报文请求的线圈数
    msgs = msgs.left(num);
    emit toUishowMsg("*****************成功读出线圈的数据***************\n");
    emit toUishowMsg(QString("起始地址:%1").arg(startaddr)+"             "+QString("数量:%1\r\n").arg(num));
    emit toUishowMsg(msgs+"\n");
    emit toUishowMsg("***********************************************\n");
    msgs.clear();
}
//报文寄存器数据读出提示
void analysis_modbus::ReadRegsPackMsgToShow(quint16 startaddr,quint16 num,QVector<quint16> msg)
{
    quint8 size = msg.size();
    QString msgs;
    quint16 data;
    for(quint8 i=0;i<size;i++)
    {
        QString str;
        data= msg.at(i);
        str = QString("%1 ").arg(data);
        msgs+=str;
    }
    emit toUishowMsg("*****************成功读出寄存器的数据***************\n");
    emit toUishowMsg(QString("起始地址:%1").arg(startaddr)+"             "+QString("数量:%1\r\n").arg(num));
    emit toUishowMsg(msgs+"\n");
    emit toUishowMsg("***********************************************\n");
    msgs.clear();
}
//报文线圈数据写入提示
void analysis_modbus::WirteCoilPackMsgToShow(quint16 startaddr,quint16 num,QByteArray msg)
{
    quint8 size = msg.size();
    QString msgs;
    for(quint8 i=0;i<size;i++)
    {
        //先转化为2进制字符串
        QString str = QString::number((quint8)msg.at(i),2);
        //再转化为2进制整形，由二进制整形转化为8位2进制字符串前面自动补0，从而保证8位
        str = QString("%1").arg((quint8)str.toInt(NULL,2),8,2,QChar('0'));
        //8bit字节倒转
        byteReverse(str);
        //添加到数据中
        msgs += str;
    }
    //去除填充的0位，读出请求报文请求的线圈数
    msgs = msgs.left(num);
    emit toUishowMsg("*****************成功写入线圈的数据***************\n");
    emit toUishowMsg(QString("起始地址:%1").arg(startaddr)+"             "+QString("数量:%1\r\n").arg(num));
    emit toUishowMsg(msgs+"\n");
    emit toUishowMsg("***********************************************\n");
    msgs.clear();
}
//报文寄存器数据写入提示
void analysis_modbus::WirteRegsPackMsgToShow(quint16 startaddr,quint16 num,QVector<quint16> msg)
{
    quint8 size = msg.size();
    QString msgs;
    quint16 data;
    for(quint8 i=0;i<size;i++)
    {
        QString str;
        data= (quint16)msg.at(i);
        str = QString("%1 ").arg(data);
        msgs+=str;
    }
    emit toUishowMsg("*****************成功写入寄存器的数据***************\n");
    emit toUishowMsg(QString("起始地址:%1").arg(startaddr)+"             "+QString("数量:%1\r\n").arg(num));
    emit toUishowMsg(msgs+"\n");
    emit toUishowMsg("***********************************************\n");
    msgs.clear();
}
void analysis_modbus::GetData0X01(QByteArray &coilsDataArr,quint16 BeginAddress,quint16 Number)
{
    //声明读取的数据字符串
    QString getDataString;
    quint8 responseMessageByteNum;
    //求响应报文字节数
    responseMessageByteNum = (quint8)((Number + 7) / 8);

    //从数据表中读取需要数量的线圈数据,形成二进制形式字符串
    for(quint16 i = BeginAddress; i < (BeginAddress + Number); i++)
    {
        //读出线圈数据
        QString buffer = readseting->value("Section" + QString::number(i+1) + "/coil").toString();
        if(buffer == "1")
        {
            getDataString += "1";
        }
        else
        {
            getDataString += "0";
        }
    }
    //二进制字符串补0
    for(int i = 1; i <= (8*responseMessageByteNum - Number); i++)
    {
        getDataString += "0";
    }
    //coilsDataArr.resize(responseMessageByteNum);
    //将二进制字符串按字节填入响应报文数组
    for(int i = 0; i < responseMessageByteNum; i++)
    {
        //对8位1字节进行反转处理
        QString buffer = getDataString.mid((8 * i),8);
        //字节反转
        byteReverse(buffer);
        //存入响应报文数组
        coilsDataArr[i] = buffer.toInt(NULL,2);
    }
}
//0x0f功能码 写入线圈数据  单个线圈
void analysis_modbus::WriteData0X0F(quint16 satrt,QString CoilData)
{
    //更新ini文件数据
    for(int j=0,k=satrt;j<CoilData.length();j++,k++)
    {
        QString s = "Section" + QString::number(k+1) + "/coil";
        quint8 coildata;
        if(CoilData.at(j)=='1')
        {
            coildata = 1;
        }
        else
        {
            coildata = 0;
        }
        readseting->setValue(s,coildata);
    }
}
//0x0f功能码 将16进制字节数组转化为 2进制字符串
QString analysis_modbus::HexByteArrayToBinString(QByteArray DataArray)
{
    //2进制字符串的长度
    quint16 DataArrayLength;
    DataArrayLength = DataArray.size();
    QString res;
    for(int i = 0; i < DataArrayLength; i++)
    {
        //先转化为2进制字符串
        QString str = QString::number((quint8)DataArray.at(i),2);
        //再转化为2进制整形，由二进制整形转化为8位2进制字符串前面自动补0，从而保证8位
        str = QString("%1").arg((quint8)str.toInt(NULL,2),8,2,QChar('0'));
        //8bit字节倒转
        byteReverse(str);
        res += str;
    }
    return res;
}

